package com.unlcn.ils.kas.service.sysadmin.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.unlcn.ils.kas.dao.mapper.sysadmin.RoleMapper;
import com.unlcn.ils.kas.dao.mapper.sysadmin.RolePermissionMapper;
import com.unlcn.ils.kas.dao.model.sysadmin.Permission;
import com.unlcn.ils.kas.dao.model.sysadmin.Role;
import com.unlcn.ils.kas.dao.model.sysadmin.RolePermission;
import com.unlcn.ils.kas.service.sysadmin.PermissionService;
import com.unlcn.ils.kas.service.sysadmin.RoleService;
import com.unlcn.ils.kas.service.util.BaseException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class RoleServiceImpl implements RoleService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionServiceImpl.class);
    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    @Autowired
    private PermissionService permissionService;

    @Override
    public List<Role> queryRolesByUid() throws Exception {
        return null;
    }

    @Override
    public Page<Role> queryRolePage(Page<Role> page) throws Exception {
        EntityWrapper<Role> ew = new EntityWrapper<>();
        page.setRecords(roleMapper.selectPage(page, ew));
        return page;
    }

    // zgx:级联删除permission、user数据；返回值处理
    @Override
    public int delRole(List<Integer> roleIds) throws Exception {
        if (Objects.equals(roleIds, null)) {
            LOGGER.error("RoleServiceImpl.delRole param rids must not be null ");
            throw new IllegalArgumentException("角色id不能为空");
        }
        return roleMapper.deleteBatchIds(roleIds);
    }

    @Override
    public Role addRole(Role role) throws Exception {
        role.setCtime(new Date().getTime());
        if (StringUtils.isBlank(role.getName())) {
            LOGGER.error("RoleServiceImpl.addRole param Name must not be null ");
            throw new IllegalArgumentException("角色名称不能为空");
        } else {
            // 校验角色名称
            EntityWrapper<Role> ew = new EntityWrapper<Role>();
            ew.eq("name", role.getName());
            int count = roleMapper.selectCount(ew);
            if (count > 0) {
                LOGGER.error("RoleServiceImpl.addRole Name already exists ");
                throw new IllegalArgumentException("角色名称已存在");
            }
        }
        int i = roleMapper.insert(role);
        if (i > 0) {
            return role;
        } else {
            throw new BaseException(1000, "插入失败");
        }
    }

    @Override
    public int updateRole(Role role) throws Exception {
        if (Objects.equals(role.getId(), null)) {
            LOGGER.error("RoleServiceImpl.addRole param id must not be null ");
            throw new IllegalArgumentException("角色id不能为空");
        }
        if (StringUtils.isNotBlank(role.getName())) {
            EntityWrapper<Role> ew = new EntityWrapper<Role>();
            ew.eq("name", role.getName()).ne("id", role.getId());
            int count = roleMapper.selectCount(ew);
            if (count > 0) {
                LOGGER.error("RoleServiceImpl.addRole Name already exists ");
                throw new IllegalArgumentException("角色名称已存在");
            }
        }
        return roleMapper.updateAllColumnById(role);
    }

    @Override
    public Role getRoleById(Integer id) throws Exception {
        if (Objects.equals(id, null)) {
            LOGGER.error("RoleServiceImpl.queryById param id must not be null ");
            throw new IllegalArgumentException("角色id不能为空");
        }
        return roleMapper.selectById(id);
    }

    @Override
    public Integer assignPermission(Integer roleId, List<Integer> permissionIds) throws Exception {
        if (Objects.equals(roleId, null)) {
            LOGGER.error("RoleServiceImpl.assignPermission param rid must not be null ");
            throw new IllegalArgumentException("角色id不能为空");
        }

        // 得到所指派的权限
        List<Permission> assignPermissions = permissionService.listPermissionByIds(permissionIds);
        List<Permission> allPermissions = permissionService.listAllPermission();

        // 迭代得到指派权限的上级权限(目录)，前端只传递叶子节点权限
        List<Permission> parentPerm = new ArrayList<>();
        for (Permission assign : assignPermissions) {
            setParentPermission(assign, parentPerm, allPermissions);
        }

        // 得到不重复的权限
        List<Integer> assignPermissIds = getNoRepeatPermIds(assignPermissions, parentPerm);

        // 获取数据库中的角色对应的权限
        EntityWrapper<RolePermission> ew = new EntityWrapper<>();
        ew.eq("role_id", roleId);
        List<RolePermission> dbRolePermissions = rolePermissionMapper.selectList(ew);

        List<Integer> dbRolePermissionIds = new ArrayList<>();
        dbRolePermissions.stream()
                .forEach(dbRolePermission -> dbRolePermissionIds.add(dbRolePermission.getPermissionId()));

        try {
            authorize(roleId, assignPermissIds, dbRolePermissionIds);
            return 1;
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 循环授权
     * 
     * @param roleId              角色ID
     * @param assignPermissIds    新指派权限ID
     * @param dbRolePermissionIds 数据库已存权限ID
     * @return
     */
    @Transactional
    private void authorize(Integer roleId, List<Integer> assignPermissIds, List<Integer> dbRolePermissionIds)
            throws Exception {
        // 循环删除数据库有，但指派权限中不包含的权限
        for (Integer permId : dbRolePermissionIds) {
            if (!assignPermissIds.contains(permId)) {
                EntityWrapper<RolePermission> ew = new EntityWrapper<>();
                ew.eq("role_id", roleId).eq("permission_id", permId);
                rolePermissionMapper.delete(ew);
            }
        }

        // 循环增加指派权限中有，但数据库中不包含的权限
        for (Integer permissionId : assignPermissIds) {
            if (!dbRolePermissionIds.contains(permissionId)) {
                RolePermission rolePermission = new RolePermission();
                rolePermission.setRoleId(roleId);
                rolePermission.setPermissionId(permissionId);
                rolePermissionMapper.insert(rolePermission);
            }
        }
    }

    private boolean contain(Integer aim, List<Integer> collection) {
        for (Integer i : collection) {
            if (aim.equals(i))
                return true;
        }
        return false;
    }

    @Override
    public List<Role> listAll() throws Exception {
        return roleMapper.selectList(null);
    }

    @Override
    public List<Permission> listOwnPermission(Integer roleId) {
        List<Permission> ownPermissions = roleMapper.selectRolePermission(roleId, 1);
        if (Objects.equals(ownPermissions, null))
            return null;
        List<Permission> menuPermissions = new LinkedList<>();
        for (Permission permission : ownPermissions) {
            if (permission.getType().equals(2)) {
                menuPermissions.add(permission);
            }
        }
        return menuPermissions;
    }

    /**
     * 设置父级目录
     * 
     * @param childPerm
     * @param result
     * @param source
     */
    private void setParentPermission(Permission childPerm, List<Permission> result, List<Permission> source) {
        for (Permission perm : source) {
            if (perm.getId().equals(childPerm.getPid())) {
                result.add(perm);
                setParentPermission(perm, result, source);
            }
        }
    }

    /**
     * 得到不重复的权限ID
     * 
     * @param parentMenu
     * @param parentDir
     * @return
     */
    private List<Integer> getNoRepeatPermIds(List<Permission> parentMenu, List<Permission> parentDir) {
        List<Integer> permIds = new ArrayList<>();

        for (Permission permission : parentMenu) {
            if (!contain(permission.getId(), permIds)) {
                permIds.add(permission.getId());
            }
        }

        for (Permission permission : parentDir) {
            if (!contain(permission.getId(), permIds)) {
                permIds.add(permission.getId());
            }
        }
        return permIds;
    }
}
